package com.umfwechat.util;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.Hashtable;

@SuppressWarnings("unchecked")
public class Serial {
	private static final Hashtable serials = new Hashtable();
	private static final Hashtable fchannels = new Hashtable();

	public Serial() {
	}

	public static long next() {
		return next("");
	}

	@SuppressWarnings("resource")
	public synchronized static long next(String app) {
		try {
			String appKey;
			FileChannel fc;
			MappedByteBuffer serial;
			appKey = (new StringBuilder()).append(
					app).append(".serial").toString();
			fc = (FileChannel) fchannels.get(appKey);
			serial = (MappedByteBuffer) serials.get(appKey);
			long serno;
			if (serial == null) {
				RandomAccessFile RAFile = new RandomAccessFile(appKey, "rw");
				if (RAFile.length() < 8L)
					RAFile.writeLong(0L);
				fc = RAFile.getChannel();
				int size = (int) fc.size();
				serial = fc.map(
						java.nio.channels.FileChannel.MapMode.READ_WRITE, 0L,
						size);
				fchannels.put(appKey, fc);
				serials.put(appKey, serial);
			}
			FileLock flock = fc.lock();
			serial.rewind();
			serno = serial.getLong();
			serno++;
			serial.flip();
			serial.putLong(serno);
			flock.release();
			return serno;
		} catch (IOException e) {
			e.printStackTrace();
			return 0L;
		}
	}
	@SuppressWarnings("resource")
	public synchronized static long next(String app,String filePath) {
		try {
			String appKey;
			FileChannel fc;
			MappedByteBuffer serial;
			filePath = StringUtil.trim(filePath);
			StringBuilder sb = new StringBuilder(filePath);
			if (!"".equals(filePath)) {
				if (!filePath.endsWith(File.separator)) {
					sb.append(File.separator);
				}
			}
			appKey = sb.append(app).append(".serial").toString();
			fc = (FileChannel) fchannels.get(appKey);
			serial = (MappedByteBuffer) serials.get(appKey);
			long serno;
			if (serial == null) {
				RandomAccessFile RAFile = new RandomAccessFile(appKey, "rw");
				if (RAFile.length() < 8L)
					RAFile.writeLong(0L);
				fc = RAFile.getChannel();
				int size = (int) fc.size();
				serial = fc.map(
						java.nio.channels.FileChannel.MapMode.READ_WRITE, 0L,
						size);
				fchannels.put(appKey, fc);
				serials.put(appKey, serial);
			}
			FileLock flock = fc.lock();
			serial.rewind();
			serno = serial.getLong();
			serno++;
			serial.flip();
			serial.putLong(serno);
			flock.release();
			return serno;
		} catch (IOException e) {
			e.printStackTrace();
			return 0L;
		}
	}
	
	public synchronized static void update(String app, long serno){
		long serial = next(app);
		next(app, serno - serial);
	}
	
	private static void next(String app, long distance) {
		try {
			String appKey;
			FileChannel fc;
			MappedByteBuffer serial;
			appKey = (new StringBuilder()).append(
					app).append(".serial").toString();
			fc = (FileChannel) fchannels.get(appKey);
			serial = (MappedByteBuffer) serials.get(appKey);
			long serno;
			if (serial == null) {
				RandomAccessFile RAFile = new RandomAccessFile(appKey, "rw");
				if (RAFile.length() < 8L)
					RAFile.writeLong(0L);
				fc = RAFile.getChannel();
				int size = (int) fc.size();
				serial = fc.map(
						java.nio.channels.FileChannel.MapMode.READ_WRITE, 0L,
						size);
				fchannels.put(appKey, fc);
				serials.put(appKey, serial);
			}
			FileLock flock = fc.lock();
			serial.rewind();
			serno = serial.getLong();
			serno += distance;
			serial.flip();
			serial.putLong(serno);
			flock.release();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public static void main(String args[]) throws IOException {
//		for (int c = 10; c-- > 0;) {
//			System.out.println(next("busi"));
//			System.out.println(next("platform"));
//		}
		update("Order", new Long("100"));
		System.out.println(next("Order"));
	}
}
